package assembler;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import javax.swing.text.BadLocationException;

import fuentes.Simbolo;
import fuentes.SimboloTerceto;
import fuentes.TablaSimbolos;
import fuentes.Terceto;

/**
 * Esta clase genera el codigo assembler a partir de un arreglo de tercetos.
 * Como salida de la generacion se crea un fichero con extension .asm
 * Para poder ejecutar el codigo resultante es necesario instalar TASM y mediante la linea de 
 * comandos de windows ("cmd") se ejecutan los siguientes comandos:
 * 		%PATH DE TASM%\BIN> tasm fichero.asm
 * 		%PATH DE TASM%\BIN> tlink fichero.obj
 * 		%PATH DE TASM%\BIN> fichero.exe
 * @author Agustin Burgos
 *
 */
public class GeneradorAssembler {

	private Vector<String> codigo, declaracionDatos;
	private Vector<Terceto> tercetos;
	private PiscinaRegistros registros;
	private Stack<String> comparadores;
	private Long contadorAux;
	private Long contadorFloat;
	private String path;
	public final double LIMITESUMA = 3.40282347e38;

	public GeneradorAssembler(Vector<Terceto> tercetos, String path) {
		super();
		this.tercetos = tercetos;
		this.path = path;
		codigo = new Vector<String>();
		declaracionDatos = new Vector<String>();
		new Stack<Terceto>();
		registros = new PiscinaRegistros();
		comparadores = new Stack<String>();
		contadorAux = new Long(0);
		contadorFloat=new Long(0);
	}

	public void generaCodigo() throws IOException {
		declaracionDatos.add(".MODEL small");
		declaracionDatos.add(".STACK 200h");
		declaracionDatos.add(".DATA");
		definirDatos(declaracionDatos);
		codigo.add(".CODE");
		codigo.add(".386");
		codigo.add("START:");
		codigo.add("FINIT");
		codigo.add("    MOV  AX, @data");
		codigo.add("    MOV DS, AX");
		generaCodigoTercetos();
		realizarFinal();
		generaErrores();
		codigo.add("END START");
		File f = new File(path);
		PrintWriter pw = new PrintWriter(new FileWriter(f));
		for (Iterator<String> iterator = declaracionDatos.iterator(); iterator.hasNext();) {
			String type = (String) iterator.next();
			System.out.println(type);
			pw.println(type);
		}
		for (Iterator<String> iterator = codigo.iterator(); iterator.hasNext();) {
			String type = (String) iterator.next();
			System.out.println(type);
			pw.println(type);
		}
		pw.close();
	}

	private void definirDatos(Vector<String> codigo) {

		codigo.add("    errorRestaNegativa DB 'Resta negativa en variable sin signo$'");
		codigo.add("    overflowSuma DB 'Overflow en suma$'");
		codigo.add("    %auxFloat DD ?");
		codigo.add("    %limiteFloat DD "+ LIMITESUMA);
		TablaSimbolos ts = TablaSimbolos.getInstance();
		Vector<Simbolo> aux = ts.getSimbolos();
		for (int i = 0; i < aux.size(); i++) {
			if (aux.get(i).getNombre().equals("ID")) {
				if (aux.get(i).isDeclarado()) 
				{
					codigo.add("    "+ aux.get(i).getValor().toUpperCase() + " DD ?");
				}
			} else if (aux.get(i).getNombre().equals("TEXTO")) {
				aux.get(i).setNombreVar("_texto" + contadorAux.toString());
				contadorAux++;
				codigo.add("    " + aux.get(i).getNombreVar() + " DB '"
						+ aux.get(i).getValor() + "$'"
						+ "         ;espacio reservado para cadena ");
			}
			else if (aux.get(i).getNombre().equals("CTE")&&(aux.get(i).getTipo().equals("float")))
			{				
				aux.get(i).setNombreVar(aux.get(i).getValor());
				aux.get(i).setValor("_variableFloat"+contadorFloat.toString());
				contadorFloat++;
				codigo.add("    " + aux.get(i).getValor() + " DD " + aux.get(i).getNombreVar() + "	;espacio reservado para las ctes Float");
			}
		}
	}

	private void generaCodigoTercetos(){
		for (int i = 0; i < tercetos.size(); i++) 
		{
			if (esOperador(tercetos.elementAt(i).getOperador()))
			{
				realizarOperacion(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().equals("BF"))
			{
				realizarSaltoFalso(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().equals("BI"))
			{
				realizarSaltoIncondicional(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().equals("BT"))
			{
				realizarSaltoVerdadero(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().equals("ultof"))
			{
				//Falta realizar conversion de tipo
				realizarConversionTipo(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().equals("PRINT"))
			{
				realizarPrint(tercetos.elementAt(i));
			}
			else
			if (tercetos.elementAt(i).getOperador().contains("etiqueta"))
			{
				codigo.add(tercetos.elementAt(i).getOperador()+":");
			}
			
		}
	}
	

	private boolean esOperador(String cadena) {
		return ((cadena.contains("+")) || (cadena.equals("-"))
				|| (cadena.contains("*")) || (cadena.contains("/"))
				|| (cadena.contains(":-")) || (cadena.contains("<"))
				|| (cadena.contains(">")) || (cadena.contains("<="))
				|| (cadena.contains(">=")) || (cadena.contains("="))
				|| (cadena.contains("<>")));
	}

	private void realizarConversionTipo(Terceto terceto) {
		SimboloTerceto aux1 = terceto.getOperando1();
		
		String aux = "_auxF" + contadorAux.toString();
		declaracionDatos.add("    " + aux + " DD ?");
		contadorAux++;
		
		if (((aux1).getNombre().equals("reg") || (aux1).getNombre().equals("CTE")))
		{
			codigo.add("    MOV " + aux + ", " + aux1.getValor());
			codigo.add("    FILD "+ aux);
		}
		else
		if ((aux1).getNombre().equals("ID"))
			codigo.add("    FILD "+ aux1.getValor()); 
		
		codigo.add("    FSTP " + aux);
		Simbolo S=new Simbolo("ID", aux, "float");
		terceto.setReg(S);
	}
	
	private void realizarOperacion(Terceto terceto) {
		if (terceto.getOperador().equals("+"))
			realizarSuma(terceto);
		else 
		if (terceto.getOperador().equals("-"))
			realizarResta(terceto);
		else 
		if (terceto.getOperador().equals("*"))
			realizarMultiplicacion(terceto);
		else
		if (terceto.getOperador().equals("/"))
			realizarDivision(terceto);
		else
		if (terceto.getOperador().equals(":-"))
			realizarAsignacion(terceto);
		else 
		{
			comparadores.push(terceto.getOperador());
			realizarComparacion(terceto);
		}
	}

	private String getVarFloatAux(){
		String aux = "_auxF" + contadorAux.toString();
		
		declaracionDatos.add("    " + aux + " DD ?");
		contadorAux++;
		return aux;
	}
	
	private void realizarSuma(Terceto terceto) {
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();

		if (((aux1).getNombre().equals("ID") || (aux1).getNombre().equals("CTE")) && ((aux2).getNombre().equals("ID") || (aux2).getNombre().equals("CTE"))) 
		{
			//Los dos operandos son Simbolos
			if (aux1.getTipo().equals("ulong")) 
			{
				String reg = registros.get32bits();
				if (reg == null) 
				{
					liberarRegistro("ECX","ulong");
					reg = registros.get32bits();
				}
				codigo.add("    MOV " + reg + ", " + aux2.getValor());
				codigo.add("    ADD " + reg + ", " + aux1.getValor());
				codigo.add("    JC overflow");
				Simbolo simboloNuevo = new Simbolo("reg", reg);
				terceto.setReg(simboloNuevo);
			} 
			else 
			if (aux1.getTipo().equals("float"))
			{
				// Aplilo en el registro.
					codigo.add("    FLD	" + aux1.getValor());
				// Realizo la suma.
							
				codigo.add("    FADD "+ aux2.getValor());
				
				String aux = this.getVarFloatAux();
				codigo.add("    FSTP " + aux);
				
				generarComprobacionOverflow(aux);
				
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		} else 
		if ((aux1.getNombre().equals("reg")) && (aux2.getNombre().equals("reg"))) 
		{
			//Los dos operandos son tercetos, utilizo el resutado de cada terceto
			//para generar el assembler
			codigo.add("    ADD " + (aux2.getValor()) + ", " + aux1.getValor());
			codigo.add("    JC overflow");
			terceto.setReg(((Terceto) aux2).getReg());
			registros.vaciarRegistro(aux1.getValor());
		}else
		if (aux1.getNombre().equals("reg") && (aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE"))) 
		{
			if (aux2.getTipo().equals("ulong")) 
			{
				codigo.add("    ADD " + aux1.getValor() + ", "
							+ aux2.getValor());
				codigo.add("	JC overflow");
				terceto.setReg(((Terceto) aux1).getReg());
			}
			else 
			if (aux2.getTipo().equals("float")) 
			{
				codigo.add("    FLD	" + aux1.getValor());

				// Realizo la suma.
				codigo.add("    FADD "+ aux2.getValor());
				
				String aux = this.getVarFloatAux();

				codigo.add("    FSTP " + aux);
				generarComprobacionOverflow(aux);
				Simbolo S=new Simbolo("ID", aux);
				terceto.setReg(S);
				registros.vaciarRegistro(aux1.getValor());
			}
		}else
		if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals("CTE"))
					&& (aux2.getNombre().equals("reg"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				codigo.add("    ADD " + aux2.getValor() + ", "
							+ aux1.getValor());
				codigo.add("	JC overflow");
				terceto.setReg(((Terceto) aux2).getReg());
			}
			else
			if (aux1.getTipo().equals("float")) 
			{
				// Cargo

				codigo.add("    FLD	" + aux1.getValor());

				// Realizo la suma.
				codigo.add("    FADD " + aux2.getValor());
				String aux = this.getVarFloatAux();

				codigo.add("    FSTP " + aux);
				generarComprobacionOverflow(aux);
				Simbolo S=new Simbolo("ID", aux,"float");
				
				terceto.setReg(S);
				registros.vaciarRegistro(aux2.getValor());
			}
		}
		
	}

	private void generarComprobacionOverflow(String aux) {
		
		codigo.add("    FLD	" + aux);
			
		codigo.add("    FCOM %limiteFloat");
		liberarRegistro("AX","ulong");
        codigo.add("    FSTSW AX");
        codigo.add("    FWAIT");
        codigo.add("    SAHF");
        codigo.add("    JA overflow");
		
	}

	private void realizarResta(Terceto terceto) {
		
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();
		
		if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals("CTE")) &&
			(aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				String reg = registros.get32bits();
				if (reg == null) 
				{
					liberarRegistro("ECX","ulong");
					reg = registros.get32bits();
				}
				codigo.add("    MOV " + reg + ", " + aux2.getValor());
				codigo.add("    SUB " + reg + ", " + aux1.getValor());
				
				//Compruebo resultado resta negativa
				String aux = this.getVarAux();
				codigo.add("    MOV " + aux + ", " + aux2.getValor());
				codigo.add("    CMP " + aux + ", "+ aux1.getValor());
				codigo.add("    JB errorRestaNeg");

				Simbolo simboloNuevo = new Simbolo("reg", reg);
				terceto.setReg(simboloNuevo);
			} 
			else 
			if (aux1.getTipo().equals("float")) 
			{ 
				codigo.add("    FLD	" + aux2.getValor());

				// Realizo la resta.
				codigo.add("    FSUB "+ aux1.getValor());
				
				String aux = "_auxF" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;
				
				codigo.add("    FSTP " + aux);
				
				Simbolo S=new Simbolo("ID", aux, "float");
				
				terceto.setReg(S);
			}
		} 
		else 
		if ((aux1.getNombre().equals("reg")) && (aux2.getNombre().equals("reg"))) 
		{
			String aux = this.getVarAux();
			codigo.add("    MOV " + aux + ", " + aux2.getValor());
			codigo.add("    SUB " + aux2.getValor() + ", " + aux1.getValor());
			
			//Compruebo resultado resta negativa
			codigo.add("    CMP " + aux + ", "+ aux1.getValor());
			codigo.add("    JB errorRestaNeg");
			
			terceto.setReg(((Terceto) aux2).getReg());
			registros.vaciarRegistro(aux1.getValor());
		} 
		else
		if ((aux1.getNombre().equals("reg")) && (aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE"))) 
		{
			if (aux2.getTipo().equals("ulong")) 
			{
				String reg = registros.get32bits();
				if (reg == null) 
				{
					liberarRegistro("ECX","ulong");
					reg = registros.get32bits();
				}
				codigo.add("    MOV " + reg + ", " + aux2.getValor());
				codigo.add("    SUB " + reg + ", " + aux1.getValor());
				
				//Compruebo resultado resta negativa
				String aux = this.getVarAux();
				codigo.add("    MOV " + aux + ", " + aux2.getValor());
				codigo.add("    CMP " + aux + ", "+ aux1.getValor());
				codigo.add("    JB errorRestaNeg");
				Simbolo simboloNuevo = new Simbolo("reg", reg);
				terceto.setReg(simboloNuevo);
				registros.vaciarRegistro(aux1.getValor());
			} 
			else 
			if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals("CTE")) && (aux2.getNombre().equals("reg"))) 
			{
				if (aux1.getTipo().equals("ulong")) 
				{
					String aux = this.getVarAux();
					codigo.add("    MOV " + aux + ", " + aux2.getValor());
					codigo.add("    SUB " + aux2.getValor() + ", "
							+ aux1.getValor());
						
					//Compruebo resultado resta negativa
					codigo.add("    CMP " + aux + ", "+ aux1.getValor());
					codigo.add("    JB errorRestaNeg");
//					codigo.add("    JS errorRestaNeg");
					terceto.setReg(((Terceto) aux2).getReg());
				}

			}
		}
			
		
	}

	private void realizarMultiplicacion(Terceto terceto) {
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();

		if ((aux1.getNombre().equals("ID")) && (aux2.getNombre().equals("ID")))
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio) 
				{
					liberarRegistro("EAX","ulong");
				}
				codigo.add("    MOV EAX, " + aux2.getValor());
				codigo.add("    MUL " + aux1.getValor());
				Simbolo simboloNuevo = new Simbolo("reg", "EAX");
				terceto.setReg(simboloNuevo);
			} 
			else 
			if (aux1.getTipo().equals("float")) 
			{
				codigo.add("    FLD	" + aux1.getValor());

				// Realizo la multiplicacion.
				codigo.add("    FMUL "+aux2.getValor());

				String aux = "_aux" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;

				codigo.add("    FSTP " + aux);
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		} 
		else
		if ((aux1.getNombre().equals("CTE")) && (aux2.getNombre().equals("CTE"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				String reg = registros.get32bits();
				if (reg == null) 
				{
					liberarRegistro("ECX","ulong");
					reg = registros.get32bits();
				}
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio) 
				{
					liberarRegistro("EAX","ulong");
				}
				codigo.add("    MOV " + reg + ", " + aux1.getValor());
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    MUL " + reg);
				Simbolo simboloNuevo = new Simbolo("reg", "EAX");
				terceto.setReg(simboloNuevo);
				registros.vaciarRegistro(reg);
			} 
			else
			if ( aux1.getTipo().equals("float")) 
			{
				codigo.add("    FLD	" + aux1.getValor());
				// Realizo la multiplicacion.
				codigo.add("    FMUL "+ aux2.getValor());

				String aux = "_aux" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;

				codigo.add("    FSTP " + aux);
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}

		}
		else 
		if ((aux1.getNombre().equals("CTE")) && (aux2.getNombre().equals("ID"))) 
		{
			if (aux1.getTipo().equals("ulong") && aux2.getTipo().equals("ulong"))
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio) 
				{
					liberarRegistro("EAX","ulong");
				}
				codigo.add("    MOV " + "EAX" + ", " + aux1.getValor());
				codigo.add("	MUL " + aux2.getValor());
				Simbolo simboloNuevo = new Simbolo("reg", "EAX");
				terceto.setReg(simboloNuevo);

			} 
			else
			if ( aux1.getTipo().equals("float")) 
			{	
				codigo.add("    FLD	" + aux1.getValor());
				// Realizo la multiplicacion.
				codigo.add("    FMUL "+ aux2.getValor());

				String aux = "_aux" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;

				codigo.add("    FSTP " + aux);
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		} 
		else
		if ((aux1.getNombre().equals("ID")) && (aux2.getNombre().equals("CTE"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{

				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio) {
					liberarRegistro("EAX","ulong");
				}
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    MUL " + aux1.getNombre());
				Simbolo simboloNuevo = new Simbolo("reg", "EAX");
				terceto.setReg(simboloNuevo);

			} 
			else 
			if ( aux1.getTipo().equals("float")) 
			{
				codigo.add("    FLD	" + aux1.getValor());
				// Realizo la multiplicacion.
				codigo.add("    FMUL "+ aux2.getValor());

				String aux = "_aux" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;

				codigo.add("    FSTP " + aux);
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}

		}
		else
		if ((aux1.getNombre().equals("reg")) && (aux2.getNombre().equals("reg"))) 
		{
			if (!aux2.getValor().equals("EAX")) 
			{
				if (!aux1.getValor().equals("EAX")) 
				{
					boolean vacio = registros.getEAX();
					// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable
					// aux
					if (!vacio) 
					{
						liberarRegistro("EAX","ulong");
					}
					codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
					codigo.add("    MUL " + ", " + aux1.getValor());
					codigo.add("    MOV " + aux2.getValor()+", EAX");
					terceto.setReg(((Terceto) aux2).getReg());
					registros.vaciarRegistro(aux1.getValor());
					registros.vaciarRegistro("EAX");
				}
				else 
				{
					codigo.add("    MUL " + ", " + aux2.getValor());
					terceto.setReg(((Terceto) aux1).getReg());
					registros.vaciarRegistro(aux2.getValor());
				}
			}
			else 
			{
				codigo.add("    MUL " + ", " + aux1.getValor());
				terceto.setReg(((Terceto) aux2).getReg());
				registros.vaciarRegistro(aux1.getValor());
			}
		}
		else 
		{
			if (aux1.getNombre().equals("reg") && ((aux2.getNombre().equals("ID")) || (aux2.getNombre().equals("CTE")))) 
			{	
				if (aux2.getTipo().equals("ulong"))
				{
					if (aux1.getValor().equals("EAX")) 
					{
						codigo.add("    MUL " + aux2.getValor());
						terceto.setReg(((Terceto) aux1).getReg());
					}
					else
					{
						boolean vacio = registros.getEAX();
						// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable
						// aux
						if (!vacio)
							liberarRegistro("EAX","ulong");
						
							codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
							codigo.add("    MUL " + aux1.getValor());
							codigo.add("    MOV " + aux2.getValor()+", EAX");
							registros.vaciarRegistro(aux1.getNombre());
							registros.vaciarRegistro("EAX");
							terceto.setReg(((Terceto) aux2).getReg());
					}
				}
			} 
			else
			if (((aux1.getNombre().equals("ID")) || (aux1.getNombre()
					.equals("CTE"))) && (aux2.getNombre().equals("reg"))) 
			{
				if (aux2.getValor().equals("EAX")) 
				{
					codigo.add("    MUL " + aux1.getValor());
					codigo.add("    MOV " + aux2.getValor()+", EAX");
					terceto.setReg(((Terceto) aux2).getReg());
					registros.vaciarRegistro("EAX");
				} 
				else
				{
					boolean vacio = registros.getEAX();
					// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable
					// aux
					if (!vacio) 
					{
						liberarRegistro("EAX","ulong");
					}
					codigo.add("    MOV " + "EAX" + ", " + aux1.getValor());
					codigo.add("    MUL " + aux2.getValor());
					registros.vaciarRegistro(aux2.getNombre());
					Simbolo S=new Simbolo("reg", "EAX");
					terceto.setReg(S);
				}

			}
		}
	}

	private void realizarDivision(Terceto terceto) {
		
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();
	
		if ((aux1.getNombre().equals("ID")) && (aux2.getNombre().equals("ID")))
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + aux1.getValor());
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
			}
			else 
			if(aux1.getTipo().equals("float"))
			{
				codigo.add("    FLD	" + aux2.getValor());

				// Realizo la resta.
				codigo.add("    FDIV "+ aux1.getValor());
				
				String aux = "_auxF" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;
				
				codigo.add("    FSTP " + aux);
				
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		}
		else
		if ((aux1.getNombre().equals("CTE"))
				&& (aux2.getNombre().equals("CTE"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				String r1 = "ECX";
				if (!registros.getECX())
					liberarRegistro("ECX","ulong");
				
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				if (!vacio)
					liberarRegistro("EDX","ulong");
				codigo.add("    MOV " + r1 + ", " + aux1.getValor());
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + r1);
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
				registros.vaciarRegistro(r1);

			}
			else
			if(aux1.getTipo().equals("float"))
			{
				codigo.add("    FLD	" + aux2.getValor());
				// Realizo la resta.
				codigo.add("    FDIV "+ aux1.getValor());
				
				String aux = "_auxF" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;
					
				codigo.add("    FSTP " + aux);
				
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);

			}
		}
		else
		if ((aux1.getNombre().equals("CTE"))
				&& (aux2.getNombre().equals("ID"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				if (!registros.getECX())
					liberarRegistro("ECX","ulong");
				
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    MOV " + "ECX" + ", " + aux1.getValor());
				codigo.add("    DIV  ECX");
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
			}
			else
			if(aux1.getTipo().equals("float"))
			{
				codigo.add("    FLD	" + aux2.getValor());

				// Realizo la resta.
				codigo.add("    FDIV "+ aux1.getValor());
					
				String aux = "_auxF" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;
					
				codigo.add("    FSTP " + aux);
					
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		}
		else
		if ((aux1.getNombre().equals("ID"))
				&& (aux2.getNombre().equals("CTE"))) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + aux1.getValor());
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
			}
			else
			if(aux1.getTipo().equals("float"))
			{
				codigo.add("    FLD	" + aux2.getValor());

				// Realizo la resta.
				codigo.add("    FDIV "+ aux1.getValor());
				
				String aux = "_auxF" + contadorAux.toString();
				declaracionDatos.add("    " + aux + " DD ?");
				contadorAux++;
					
				codigo.add("    FSTP " + aux);
					
				Simbolo S=new Simbolo("ID", aux, "float");
				terceto.setReg(S);
			}
		}
		else
		if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals(
				"CTE"))	&& (aux2.getNombre().equals("reg"))) 
		{
			if (!aux2.getValor().equals("EAX")) 
			{
				boolean vacio = registros.getEAX();
				// SI ESTA OCUPADO LO TENGO Q VACIAR...agrego una variable aux
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				if (!vacio)
					liberarRegistro("EDX","ulong");
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + aux1.getValor());
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
				registros.vaciarRegistro(aux2.getValor());
			} 
			else
			{
				codigo.add("    DIV " + aux1.getValor());
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
			}
		}
		else
		if ((aux1.getNombre().equals("reg"))
				&& (aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE")))
		{
			if (!aux1.getValor().equals("EAX")) 
			{
				String r1 = "ECX";
				if (!registros.getECX()) 
				{
					liberarRegistro("ECX","ulong");
				}
				
				boolean vacio = registros.getEAX();
				
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				codigo.add("    MOV " + r1 + ", " + aux1.getValor());
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + r1);
				Simbolo r = new Simbolo("reg", "EAX");

				terceto.setReg(r);
				registros.vaciarRegistro(r1);
			} 
			else
			{
				String r1 = registros.get32bits();
				if (r1 == null) 
				{
					liberarRegistro("ECX","ulong");
					r1 = registros.get32bits();
				}
				
				codigo.add("    MOV " + r1 + ", " + "EAX");
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + r1);
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
				registros.vaciarRegistro(r1);

			}
		}

		else if ((aux1.getNombre().equals("reg")) && (aux2.getNombre().equals("reg"))) 
		{
			if (!aux1.getValor().equals("EAX")) 
			{
				boolean vacio = registros.getEAX();
				
				if (!vacio)
					liberarRegistro("EAX","ulong");
				
				vacio = registros.getEDX();
				
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + aux1.getValor());
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
				registros.vaciarRegistro(aux1.getValor());
				registros.vaciarRegistro(aux2.getValor());
			} 
			else 
			{
				boolean vacio = registros.getECX();
				
				if (!vacio)
					liberarRegistro("ECX","ulong");
				
				vacio = registros.getEDX();
				
				if (!vacio)
					liberarRegistro("EDX","ulong");
				
				codigo.add("    MOV " + "ECX" + ", " + aux1.getValor());
				codigo.add("    MOV " + "EAX" + ", " + aux2.getValor());
				codigo.add("    DIV " + "ECX");
				Simbolo r = new Simbolo("reg", "EAX");
				terceto.setReg(r);
				registros.vaciarRegistro(aux2.getValor());
				registros.vaciarRegistro("ECX");
				registros.vaciarRegistro("EDX");
			}
		}
	}

	private void realizarAsignacion(Terceto terceto) {
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();
			
		if (aux1.getNombre().equals("ID") && aux2.getNombre().equals("ID")) 
		{ 
			if (aux1.getTipo().equals("ulong")) 
			{
				String r1 = registros.get32bits();
				if (r1 == null) 
				{
					liberarRegistro("ECX","ulong");
					r1 = registros.get32bits();
				}

				codigo.add("    MOV  "+r1+", "+aux1.getValor());
				codigo.add("    MOV  "+aux2.getValor()+", "+r1);

			}
			if (aux1.getTipo().equals("float"))
			{
                codigo.add("    FLD  "+aux1.getValor());
                codigo.add("    FSTP "+aux2.getValor());
            }
			
		}
		else 
		if (aux1.getNombre().equals("reg") && aux2.getNombre().equals("ID")) 
		{
			codigo.add("    MOV " + aux2.getValor() + ", " + aux1.getValor());
			registros.vaciarRegistro(aux1.getValor());
		}
		else 
		if (aux1.getNombre().equals("CTE") && aux2.getNombre().equals("ID")) 
		{
			if (aux1.getTipo().equals("ulong")) 
			{
				String r1 = registros.get32bits();
				
				if (r1 == null) 
				{
					liberarRegistro("ECX","ulong");
					r1 = registros.get32bits();
				}
				
				codigo.add("    MOV " + r1 + ", " + aux1.getValor() + "D");
				codigo.add("    MOV " + aux2.getValor() + ", " + r1);
				registros.vaciarRegistro(r1);
			}
			else 
			if (aux1.getTipo().equals("float"))
			{
				codigo.add("    FLD  "+aux1.getValor());
	            codigo.add("    FSTP "+aux2.getValor());
	        }
		}
	}

	private void realizarComparacion(Terceto terceto) {
		
		SimboloTerceto aux2 = terceto.getOperando1();
		SimboloTerceto aux1 = terceto.getOperando2();

		if (aux1.getNombre().equals("reg") && aux2.getNombre().equals("reg")) 
		{
			codigo.add("    CMP " + aux1.getValor() + ", " + aux2.getValor());
			registros.vaciarRegistro(aux1.getValor());
			registros.vaciarRegistro(aux2.getValor());
		}
		else
		if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals("CTE"))&& aux2.getNombre().equals("reg")) 
		{
			String r1 = registros.get32bits();
			
			if (r1 == null) 
			{
				if (aux2.getValor().equals("ECX"))
				{
					liberarRegistro("EDX","ulong");
				}
				else
					liberarRegistro("ECX","ulong");
				
				r1 = registros.get32bits();
			}
			codigo.add("    MOV " + r1 + ", " + aux1.getValor());
			codigo.add("    CMP " + r1 + ", " + aux2.getValor());
			registros.vaciarRegistro(r1);
			registros.vaciarRegistro(aux2.getValor());
		}
		else
		if (aux1.getNombre().equals("reg") && (aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE"))) 
		{
			String r1 = registros.get32bits();
		
			if (r1 == null) 
			{
				liberarRegistro("ECX","ulong");
				r1 = registros.get32bits();
			}
			
			codigo.add("    MOV " + r1 + ", " + aux2.getValor());
			codigo.add("    CMP " + r1 + ", " + aux1.getValor());
			registros.vaciarRegistro(r1);
			registros.vaciarRegistro(aux1.getValor());
		}
		else
		if ((aux1.getNombre().equals("ID") || aux1.getNombre().equals("CTE"))
				&& (aux2.getNombre().equals("ID") || aux2.getNombre().equals("CTE")))
		{
			if (aux1.getTipo().equals("ulong"))
			{
				String r1 = registros.get32bits();
				
				if (r1 == null) 
				{
					liberarRegistro("ECX","ulong");
					r1 = registros.get32bits();
				}
				
				codigo.add("    MOV " + r1 + ", " + aux2.getValor());
				codigo.add("    CMP " + r1 + ", " + aux1.getValor());
				registros.vaciarRegistro(r1);
			}
			else
			if (aux2.getTipo().equals("float"))
			{
				
				codigo.add("    FLD " + aux2.getValor());
				codigo.add("    FCOM " + aux1.getValor());
				liberarRegistro("AX","ulong");
		        codigo.add("    FSTSW AX");
		        codigo.add("    FWAIT");
		        codigo.add("    SAHF");
		    }
		 }
	  }

	private void realizarSaltoFalso(Terceto terceto) {
		String cmp = ((Terceto) terceto.getOperando1()).getOperador();
		String aux1 = ((Terceto) terceto.getOperando2()).getOperador();

		if (cmp.equals("<"))
			codigo.add("    JAE " + aux1); // Salta si >=
		
		else if (cmp.equals("<="))
			codigo.add("    JA " + aux1); // Salta si >
		
		else if (cmp.equals(">"))
			codigo.add("    JBE " + aux1); // Salta si <=
		
		else if (cmp.equals(">="))
			codigo.add("    JB " + aux1); // Salta si <
		
		else if (cmp.equals("="))
			codigo.add("    JNE " + aux1); // Salta si !=
		
		else if (cmp.equals("<>"))
			codigo.add("    JE " + aux1); // Salta si =
		
	}

	private void realizarSaltoIncondicional(Terceto terceto) {

		try{
		String aux1 = ((Terceto) terceto.getOperando1()).getOperador();
		codigo.add("    JMP " + aux1);
		}catch(Exception e1){
			e1.printStackTrace();
		}

	}
	
	private void realizarSaltoVerdadero(Terceto terceto) {
		String cmp = ((Terceto) terceto.getOperando1()).getOperador();
		String aux1 = ((Terceto) terceto.getOperando2()).getOperador();
		
		if (cmp.equals("<"))
			codigo.add("    JB " + aux1); // Salta si <
		else if (cmp.equals("<="))
			codigo.add("    JBE " + aux1); // Salta si <=
		else if (cmp.equals(">"))
			codigo.add("    JA " + aux1); // Salta si >
		else if (cmp.equals(">="))
			codigo.add("    JAE " + aux1); // Salta si >=		
		else if (cmp.equals("="))
			codigo.add("    JE " + aux1); // Salta si =
		else if (cmp.equals("<>"))
			codigo.add("    JNE " + aux1); // Salta si !=
	}

	private void realizarPrint(Terceto terceto) {

		SimboloTerceto aux1 = terceto.getOperando1();
		if (!registros.getEAX())
		liberarRegistro("EAX","ulong");
		if  (!registros.getEDX())
		liberarRegistro("EDX","ulong");

			codigo.add("    LEA EDX, " + aux1.getNombreVar());
			codigo.add("    MOV AH, 9");
			codigo.add("    INT 21H");
			registros.vaciarRegistro("EAX");
			registros.vaciarRegistro("EDX");
		
	}

	private String getVarAux(){
		String aux = "_aux" + contadorAux.toString();
		declaracionDatos.add("    " + aux + " DD ?");
		return aux;
	}

	private void liberarRegistro(String reg,String tipo) {

			String aux = "_aux" + contadorAux.toString();
			
			if (!reg.equals("AX"))
				declaracionDatos.add("    " + aux + " DD ?");
			else
				declaracionDatos.add("    " + aux + " DW ?");
			
			contadorAux++;
			registros.vaciarRegistro(reg);
			for (int i = 0; i < tercetos.size(); i++) 
			{
				if (tercetos.elementAt(i).getReg().getValor().equals(reg))
				{
					Simbolo r = new Simbolo("ID", aux);
					tercetos.elementAt(i).setReg(r);
				}
			}

			codigo.add ("    MOV " + aux + ", " + reg);
			
	}
		
	

	private void realizarFinal() {
		codigo.add("    MOV AH, 4CH           ; C�digo de finalizaci�n de programa");
		codigo.add("    MOV AL, 0");
		codigo.add("    INT 21H");
	}

	private void generaErrores() {

		codigo.add("errorRestaNeg: ");
		codigo.add("    LEA DX, errorRestaNegativa");
		codigo.add("    MOV AH, 9");
		codigo.add("    INT 21H");
		realizarFinal();

		codigo.add("overflow: ");
		codigo.add("    LEA DX, overflowSuma");
		codigo.add("    MOV AH, 9");
		codigo.add("    INT 21H");
		realizarFinal();
	}
}
